import type {
  MachineConfig,
  MachineOptions,
  MultiTransitionListener,
  TransitionConfig,
} from './types';

/**
 * StateMachine
 *
 * 管理多个 GameEntity 的状态，复用同一套状态机配置（config）。
 */
export class StateMachine<S extends string, E extends string> {
  private readonly config: MachineConfig<S, E>;
  private readonly states = new WeakMap<GameEntity, S>();
  private readonly listeners = new Set<MultiTransitionListener<S>>();
  private readonly options?: MachineOptions<S, E>;

  /** 判断某状态是否为“终止状态”（final） */
  private isFinalState(state: S): boolean {
    const cfg = this.config.states[state];
    if (!cfg) {
      return false;
    }
    if (cfg.final === true) {
      return true;
    }
    const { on } = cfg;
    // 若未显式标记 final，当 on 为空或未定义时，视为自然终止态
    if (!on) {
      return true;
    }
    return Object.keys(on).length === 0;
  }

  constructor(config: MachineConfig<S, E>, options?: MachineOptions<S, E>) {
    this.config = config;
    this.options = options;
  }

  /** 注册实体，可指定初始状态；默认使用 config.initial */
  register(entity: GameEntity, initial?: S): void {
    const init = initial ?? this.config.initial;
    this.states.set(entity, init);
    // 进入初始状态的 onEnter 钩子（如果存在）
    const cfg = this.config.states[init];
    if (cfg?.onEnter) {
      cfg.onEnter(entity, entity.motion, init, init);
    }
  }

  /** 取消注册（可选）。WeakMap 已能避免泄漏，但主动移除可更明确 */
  unregister(entity: GameEntity): void {
    this.states.delete(entity);
  }

  /** 获取实体当前状态；未注册时返回 undefined */
  stateOf(entity: GameEntity): S | undefined {
    return this.states.get(entity);
  }

  /** 订阅任意实体的状态迁移 */
  subscribe(listener: MultiTransitionListener<S>): () => boolean {
    this.listeners.add(listener);
    return () => this.listeners.delete(listener);
  }

  /**
   * 帧更新：如项目为 Tick 驱动，可在主循环中调用此方法。
   * 如果当前状态定义了 onUpdate，则会被调用（可异步）。
   */
  async update(entity: GameEntity, deltaTime: number): Promise<void> {
    const currentState = this.states.get(entity);
    if (!currentState) {
      return;
    }
    // 终止态不再执行 onUpdate
    if (this.isFinalState(currentState)) {
      return;
    }
    const cfg = this.config.states[currentState];
    if (!cfg?.onUpdate) {
      return;
    }
    await cfg.onUpdate(entity, entity.motion, currentState, deltaTime);
  }

  /** 判断实体在当前状态下是否可以响应 event 进行迁移（考虑 guard） */
  can(entity: GameEntity, event: E): boolean {
    const currentState = this.states.get(entity);
    if (!currentState) {
      return false;
    }
    // 终止态不可再响应任何事件
    if (this.isFinalState(currentState)) {
      return false;
    }
    const current = this.config.states[currentState];
    const raw = current.on?.[event];
    if (!raw) {
      return false;
    }
    const t: TransitionConfig<S, E> =
      typeof raw === 'string'
        ? ({ target: raw as S } as TransitionConfig<S, E>)
        : raw;
    return t.guard ? t.guard(entity, event) : true;
  }

  /** 计算实体在给定事件下的下一个状态（不改变当前状态） */
  getNextState(entity: GameEntity, event: E): S | null {
    const currentState = this.states.get(entity);
    if (!currentState) {
      return null;
    }
    // 终止态没有后继
    if (this.isFinalState(currentState)) {
      return null;
    }
    const current = this.config.states[currentState];
    const raw = current.on?.[event];
    if (!raw) {
      return null;
    }
    const t: TransitionConfig<S, E> =
      typeof raw === 'string'
        ? ({ target: raw as S } as TransitionConfig<S, E>)
        : raw;
    if (t.guard && !t.guard(entity, event)) {
      return null;
    }
    return t.target;
  }

  /**
   * 触发实体的事件并尝试迁移：若通过 guard，则执行 action 并更新该实体的当前状态
   * 返回是否发生了迁移
   */
  async send(entity: GameEntity, event: E): Promise<boolean> {
    const currentState = this.states.get(entity);
    if (!currentState) {
      return false;
    }
    // 终止态不处理任何事件
    if (this.isFinalState(currentState)) {
      return false;
    }
    const current = this.config.states[currentState];
    const raw = current.on?.[event];
    if (!raw) {
      return false;
    }
    const t: TransitionConfig<S, E> =
      typeof raw === 'string'
        ? ({ target: raw as S } as TransitionConfig<S, E>)
        : raw;
    if (t.guard && !t.guard(entity, event)) {
      return false;
    }

    const prev = currentState;
    const next = t.target;

    if (t.action) {
      await t.action(entity, event);
    }

    // 生命周期钩子：退出旧状态
    const prevConfig = this.config.states[prev];
    if (prevConfig.onExit) {
      await prevConfig.onExit(entity, entity.motion, prev, next);
    }

    this.states.set(entity, next);

    // 生命周期钩子：进入新状态
    const nextConfig = this.config.states[next];
    if (nextConfig.onEnter) {
      await nextConfig.onEnter(entity, entity.motion, prev, next);
    }
    for (const l of this.listeners) {
      l(entity, next, prev);
    }
    // 全局迁移回调（可选）
    if (this.options?.onTransition) {
      await this.options.onTransition(entity, next, prev, event);
    }
    return true;
  }
}
